#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "CmdReq.h"
#include "CmdRsp.h"
#include "point_read_write.h"
#include "los_base.h"
#include "los_swtmr.h"
#include "omip.h"
#include "omip_uart.h"
#include "atiny_adapter.h"
#include "read_and_write_flash.h"
#include "ble.h"
#include "main.h"

point_data_t *m_point_data =NULL;

PropertyValue_PR vav_get_point_data_type(char *type)
{	
	if(NULL == type) {
		return PropertyValue_PR_realValue;
	}

	if(strcmp("float", type) == 0) {
		return PropertyValue_PR_realValue;
	}
	else if(strcmp("enum", type) == 0) {
		return PropertyValue_PR_intValue;
	}
	else if(strcmp("boll", type) == 0) {
		return PropertyValue_PR_boolValue;
	}
	return PropertyValue_PR_realValue;
}


point_data_t *vav_add_point(int obj_id,flow_node_base_t *node,int (*write_point_callback)(int,int,double,point_data_t *p)) //添加点位
{
	OMIP_LOG_INFO("add point. obj_id:0x%x. sType:%s",obj_id, node->node_io_attr_ins.acio_attr_sensor_type);
	point_data_t *new_point = malloc(sizeof(point_data_t));
	memset(new_point,0,sizeof(point_data_t));
	new_point->next_point = NULL;
	new_point->obj_id = obj_id;
	new_point->max_priority = 16;
	new_point->write_point_callback =write_point_callback;
	new_point->node = node;
	new_point->priority_arr[15].used =1;
	if(node->ucnode_output) {
		new_point->data_type = vav_get_point_data_type(node->poutput_arr[0]->acnode_ioput_type);
		OMIP_LOG_INFO("output data_type:%s(%d)", node->poutput_arr[0]->acnode_ioput_type, new_point->data_type);
	}
	else if(node->ucnode_input) {
		new_point->data_type = vav_get_point_data_type(node->pinput_arr[0]->acnode_ioput_type);
		OMIP_LOG_INFO("output data_type:%s(%d)", node->pinput_arr[0]->acnode_ioput_type, new_point->data_type);
	}
	else {
		OMIP_LOG_INFO("Unknown data type");
	}
	
	//pthread_mutex_lock(&mutex);
	if(!m_point_data) {m_point_data =new_point; return new_point;} //链表为空
	point_data_t *ptr =m_point_data;
	while(ptr && ptr->next_point) {ptr =ptr->next_point;}
	ptr->next_point =new_point; //插入到链表尾部
	//pthread_mutex_unlock(&mutex);
	return new_point;
}

void vav_clear_points() //清除所有点位
{
	if(!m_point_data) {printf("return beacuse point data is null.\r\n"); return;}
	point_data_t *p, *q;
	p =m_point_data;
	q =m_point_data->next_point;
	free(p);
	while(q)
	{
		p =q;
		q =q->next_point;
		free(p);
	}
	m_point_data =NULL;
}

point_data_t *vav_get_point_by_id(int obj_id) //根据ID查找点位
{
	point_data_t *p =m_point_data;
	while(p)
	{
		if(p->obj_id ==obj_id)	return p;
		p =p->next_point;
	}
	return NULL;
}

//根据sensor_type查找点位
point_data_t *vav_get_point_by_stype(char *sensor_type) 
{
	point_data_t *p =m_point_data;
	while(p)
	{
		//if(p->obj_id ==obj_id)	return p;
		if(strcmp(p->node->node_io_attr_ins.acio_attr_sensor_type, sensor_type) ==0) {
			return p;
		}
		p =p->next_point;
	}
	return NULL;
}

UINT8 vav_get_point_priority_by_stype(char *sensor_type)
{
	point_data_t *p = vav_get_point_by_stype(sensor_type);
	if(NULL == p) {
		return 0;
	}
	return p->max_priority;
}


int vav_set_msg_to_priority_by_stype(char *sensor_type, double value, int priority)
{
	point_data_t *p = vav_get_point_by_stype(sensor_type);
	if(!p) return -1;
	p->priority_arr[priority - 1].used = 1;
	p->priority_arr[priority - 1].value = value;
	
	OMIP_LOG_DEBUG("sensor_type:%s, value:%d(x1000), priority:%d->%d",sensor_type, (int)(value), priority, p->max_priority);
	if(p->max_priority >= priority)
	{
		p->max_priority = priority;
		p->write_point_callback(p->obj_id, priority, value, p); //此处需要触发节点回调
	}
	return 0;

}


void vav_remove_priority(int obj_id, int arr_index)
{
	int i = 0;
	point_data_t *p = vav_get_point_by_id(obj_id);
	if(p)
	{
		if(arr_index < 16){
			p->priority_arr[arr_index - 1].used = 0;
			p->priority_arr[arr_index - 1].value = 0;
			if(p->max_priority == arr_index)
			{
				for(i = p->max_priority-1; i < 16; i++)
				{
					if(p->priority_arr[i].used ==1) { p->max_priority = i+1; break;}
				}
				if(16 == i) {
					p->max_priority = 16;
				}
			}
		}
		else if(arr_index == 16) {
			for(int i = 0; i < 15; i++)
			{
				p->priority_arr[i].used = 0;
				p->priority_arr[i].value = 0.0;
			}
			p->max_priority = 16;
		}
		OMIP_LOG_INFO("remove priorityobj_id:%d, sType:%s, max_priority:%d\n", 
			obj_id, p->node->node_io_attr_ins.acio_attr_sensor_type, p->max_priority);
	}
}

int vav_set_msg_to_priority(int obj_id, double value, int priority)
{
	point_data_t *p =vav_get_point_by_id(obj_id);
	if(!p) return 0;
	p->priority_arr[priority - 1].used = 1;
	p->priority_arr[priority - 1].value = value;
	
	OMIP_LOG_DEBUG("obj_id:%d, real_value:%d(x1000), priority:%d, max_priority:%d",obj_id, (int)(value), priority, p->max_priority);
	if(p->max_priority >= priority)
	{
		p->max_priority = priority;
		p->write_point_callback(obj_id, priority, value, p); //此处需要触发节点回调
	}
	return 1;

}

int vav_get_msg_to_priority(int obj_id, double *value, int *priority, char *stype)
{
	point_data_t *p =vav_get_point_by_id(obj_id);
	if(!p) return -1;
	if(1 == p->priority_arr[p->max_priority -1].used)
	{
		*value = p->priority_arr[p->max_priority -1].value;
		*priority = p->max_priority;
		strcpy(stype, p->node->node_io_attr_ins.acio_attr_sensor_type);
	}
	return 0;
}

double vav_get_point_real_value(PropertyValue_t *pro_value)
{
	if(!pro_value) return 0;
	double value = pro_value->choice.realValue;
	switch (pro_value->present)
	{
	case PropertyValue_PR_realValue:
		value =  pro_value->choice.realValue;
		break;
	case PropertyValue_PR_intValue:
		value =  pro_value->choice.intValue;
		break;
	case PropertyValue_PR_boolValue:
		value =  pro_value->choice.boolValue;
		break;
	}
	return value;
}

int vav_set_msg_to_priority_arr(int obj_id, PropertyValue_t *pro_value, int priority) //上层应用设置点位信息
{
	point_data_t *p =vav_get_point_by_id(obj_id);
	if(!p) return 0;
	if(!pro_value) return 0;

	if(p->data_type != pro_value->present) {
		OMIP_LOG_INFO("Write point, data type(%d-%d) mismatch", p->data_type, pro_value->present);
		return 0;
	}
	double value = vav_get_point_real_value(pro_value);	
	
	p->priority_arr[priority - 1].used = 1;
	p->priority_arr[priority - 1].value = value;
	
	OMIP_LOG_DEBUG("obj_id:%d, real_value:%d(x1000), priority:%d, max_priority:%d",obj_id, (int)(value), priority, p->max_priority);
	if(p->max_priority >= priority)
	{
		p->max_priority = priority;
		p->write_point_callback(obj_id, priority, value, p); //此处需要触发节点回调
	}
	return 1;
}

void vav_set_point_msg(int obj_id, double value) //控制逻辑设置点位信息
{
	point_data_t *p = vav_get_point_by_id(obj_id);
	if(!p) return;
	p->priority_arr[15].value =value;
	//printf("[%s:%d]set point, obj id:%d, stype:%s, value:%d(x1000).\r\n",__FUNCTION__,__LINE__,obj_id,p->node->node_io_attr_ins.acio_attr_sensor_type,(int)(value*1000));
}

int get_int_by_buf(uint8_t *buf) //从内存读取4字节大端整型数据
{
	int result = 0;
	for (int j = 0; j < 4; j++)	{result += buf[j] << (8 * (3 - j));}
	return result;
}

int reverse_int(int num) //4字节整型数据大小端颠倒
{
	return ((num & 0x000000ff) << 24) | ((num & 0x0000ff00) << 8) | ((num & 0x00ff0000) >> 8) | ((num & 0xff000000) >> 24);
}
int vav_set_point_to_propertyvalue(PropertyValue_t *pro_value, point_data_t *point)
{	
	int ret = 0;
	pro_value->present = point->data_type;
	double temp_value =point->priority_arr[point->max_priority-1].value;
	switch (point->data_type)
	{
	case PropertyValue_PR_realValue:
		pro_value->choice.realValue = temp_value;
		break;
	case PropertyValue_PR_intValue:
		pro_value->choice.intValue = (long)temp_value;
		break;
	case PropertyValue_PR_boolValue:
		pro_value->choice.boolValue = (BOOLEAN_t)temp_value;
		break;
	default:
		OMIP_LOG_INFO("point(%d) unknown data type(%d)!", point->obj_id, point->data_type);
		ret = -1;
		break;
	}
	return ret;
}

static void read_multi_property_rsp(uint8_t vc, int *obj_id,long mid,int size,UTF8String_t *node_id, uint16_t rsp_cmd) //读取多个点位回复
{
	static long iIndex = 1;
	CmdRsp_t *rsptr =calloc_asn(1,sizeof(CmdRsp_t));
	if(!rsptr) {printf("[%s:%d]get cmdrsp mem failed.\r\n",__FUNCTION__,__LINE__); return;}
	rsptr->errcode = 0;
	rsptr->mid = mid;
	rsptr->msgType = MsgType_terminalRsp;
	rsptr->body.present = Body_PR_bacnet;
	rsptr->body.choice.bacnet.present = BACnet_Service_ACK_PR_readPropertyMultiple;
	rsptr->body.choice.bacnet.choice.readPropertyMultiple.listOfReadAccessResults.list.array =(ReadAccessResult_t **)calloc_asn(1, sizeof(ReadAccessResult_t));
	rsptr->nodeId = node_id;
	if(!rsptr->body.choice.bacnet.choice.readPropertyMultiple.listOfReadAccessResults.list.array) {printf("[%s:%d]array mem alloc failed.\r\n",__FUNCTION__,__LINE__); return;}
	rsptr->body.choice.bacnet.choice.readPropertyMultiple.listOfReadAccessResults.list.count = size;
	rsptr->body.choice.bacnet.choice.readPropertyMultiple.listOfReadAccessResults.list.size = size;
	ReadAccessResult_t **arr = rsptr->body.choice.bacnet.choice.readPropertyMultiple.listOfReadAccessResults.list.array;
	for(int i = 0; i < size; i++)
	{
		point_data_t *point = vav_get_point_by_id(obj_id[i]);
		obj_id[i] = reverse_int(obj_id[i]);
		arr[i] = (ReadAccessResult_t *)calloc_asn(1, sizeof(ReadAccessResult_t));
		if(!arr[i]) {printf("[%s:%d]array %d mem alloc failed.\r\n",__FUNCTION__,__LINE__,i); return;}
		arr[i]->objectIdentifier.buf = (uint8_t *)&obj_id[i];
		arr[i]->objectIdentifier.size = 4;
		arr[i]->listOfResults =(struct listOfResults *)calloc_asn(1, sizeof(struct listOfResults));
		if(!arr[i]->listOfResults) {printf("listOfResults %d mem alloc failed.\r\n",i); return;}
		arr[i]->listOfResults->list.array = (struct Member **)calloc_asn(1, sizeof(struct Member *));
		if(!arr[i]->listOfResults->list.array) {printf("listOfResults->list.array %d mem alloc failed.\r\n",i); return;}
		arr[i]->listOfResults->list.size = 1;
		arr[i]->listOfResults->list.count = 1;
		arr[i]->listOfResults->list.array[0] =(struct Member *)calloc_asn(1, sizeof(struct Member));
		if(!arr[i]->listOfResults->list.array[0]) {printf("listOfResults->list.array[0] %d mem alloc failed.\r\n",i); return;}
		arr[i]->listOfResults->list.array[0]->propertyIdentifier = BACnetPropertyIdentifier_present_value;
		arr[i]->listOfResults->list.array[0]->propertyArrayIndex = &iIndex;
		if(point ==NULL) //没有找到点位
		{
			omip_printf(OMIP_INFO,"(%d:%d) \r\n",reverse_int(obj_id[i]),-9999);
			arr[i]->listOfResults->list.array[0]->readResult.present = readResult_PR_propertyAccessError;
			arr[i]->listOfResults->list.array[0]->readResult.choice.propertyAccessError.error_class = error_class_object;
			arr[i]->listOfResults->list.array[0]->readResult.choice.propertyAccessError.error_code = error_code_unknown_object;
		}
		else //找到点位,将点位的值放进去
		{
			double temp_value =point->priority_arr[point->max_priority-1].value;
			omip_printf(OMIP_INFO,"(%d:%d(x1000) ",reverse_int(obj_id[i]),(int)(temp_value*1000));
			int ret = vav_set_point_to_propertyvalue(&(arr[i]->listOfResults->list.array[0]->readResult.choice.propertyValue), point);
			if(0 == ret) {
				arr[i]->listOfResults->list.array[0]->readResult.present = readResult_PR_propertyValue;
			}
			else {
				arr[i]->listOfResults->list.array[0]->readResult.present = readResult_PR_propertyAccessError;
				arr[i]->listOfResults->list.array[0]->readResult.choice.propertyAccessError.error_class = error_class_object;
				arr[i]->listOfResults->list.array[0]->readResult.choice.propertyAccessError.error_code = error_code_invalid_data_type;
			}
			
			//arr[i]->listOfResults->list.array[0]->readResult.choice.propertyValue.present = PropertyValue_PR_realValue;
			//arr[i]->listOfResults->list.array[0]->readResult.choice.propertyValue.choice.realValue = temp_value;
		}
	}
	omip_printf(OMIP_INFO,"\r\n");
	char buf[1024] ={0};
	asn_enc_rval_t ec =(vc==OMIP_VC_CHANNEL4? uper_encode_to_buffer(&asn_DEF_CmdRsp,rsptr,buf,sizeof(buf)) : der_encode_to_buffer(&asn_DEF_CmdRsp,rsptr,buf,sizeof(buf)));
	if(ec.encoded ==-1) {printf("could not encode:%s\r\n",(ec.failed_type? ec.failed_type->name:"unknown")); goto exit;} //编码失败
	int bytesCount =(vc==OMIP_VC_CHANNEL4? ((ec.encoded + 7) >>3) : ec.encoded);
	omip_printf(OMIP_INFO,"[%s:%d]respond data len: %d \r\n",__FUNCTION__,__LINE__,bytesCount);
	if (bytesCount ==0)	goto exit;
	if(vc ==OMIP_VC_CHANNEL4)
	{
		if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_ASN1_UPER,rsp_cmd,(uint8_t *)buf,bytesCount)!=OMIP_OK)
			omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
	}
	else if(vc ==OMIP_VC_CHANNEL6)
	{
		mcu_general_send_ble(rsp_cmd,OMIP_CONTENT_FORMAT_ASN1_DER,(uint8_t *)buf,bytesCount);
	}
exit:
	for(int i = 0; i < size; i++)
	{
		if(!arr[i]) continue;
		free(arr[i]->listOfResults->list.array[0]);
		free(arr[i]->listOfResults->list.array);
		free(arr[i]->listOfResults);
		free(arr[i]);
	}
	if(arr)	free(arr);
	if(rsptr) free(rsptr);
	//SEQUENCE_free(&asn_DEF_CmdRsp,rsptr,FALSE);
}

static void write_property_rsp(uint8_t vc,long mid,long errcode,UTF8String_t *node_id) //写点位回复
{
	CmdRsp_t *rsptr = malloc(sizeof(CmdRsp_t));
	if(!rsptr) {printf("[%s:%d]get cmdrsp mem failed.",__FUNCTION__,__LINE__); return;}
	rsptr->errcode = errcode;
	rsptr->mid = mid;
	rsptr->msgType = MsgType_terminalRsp;
	rsptr->body.present = Body_PR_bacnet;
	rsptr->body.choice.bacnet.present = BACnet_Service_ACK_PR_writeProperty;
	rsptr->nodeId = node_id;
	char buf[128] ={0};
	asn_enc_rval_t ec =(vc==OMIP_VC_CHANNEL4? uper_encode_to_buffer(&asn_DEF_CmdRsp,rsptr,buf,sizeof(buf)) : der_encode_to_buffer(&asn_DEF_CmdRsp,rsptr,buf,sizeof(buf)));
	int bytesCount =(vc==OMIP_VC_CHANNEL4? ((ec.encoded + 7) >>3) : ec.encoded);
	if(vc ==OMIP_VC_CHANNEL4)
	{
		if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_ASN1_UPER,HLINK_CMD_SRV_CMD_RSP,(uint8_t *)buf,bytesCount)!=OMIP_OK)
			omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
	}
	else if(vc ==OMIP_VC_CHANNEL6)
	{
		mcu_general_send_ble(HLINK_CMD_SRV_CMD_RSP,OMIP_CONTENT_FORMAT_ASN1_DER,(uint8_t *)buf,bytesCount);
	}
	free(rsptr);
	//SEQUENCE_free(&asn_DEF_CmdRsp,rsptr,FALSE);
}

void process_point_rw(uint8_t vc, char *data, int len, uint16_t rsp_cmd) //处理ASN1格式的点位读写消息
{
	CmdReq_t *sptr = NULL;
	//asn_dec_rval_t dc = ( vc==OMIP_VC_CHANNEL4? uper_decode_complete(NULL,&asn_DEF_CmdReq,&sptr,data,len) : ber_decode(NULL,&asn_DEF_CmdReq,&sptr,data,len)); //解码消息数据
	asn_dec_rval_t dc = {0};
	if(OMIP_VC_CHANNEL4 == vc) {
		dc = uper_decode_complete(NULL, &asn_DEF_CmdReq, (void **)&sptr, data,len);
	} 
	else {
		dc = ber_decode(NULL, &asn_DEF_CmdReq, (void **)&sptr, data,len);
	}

	if(RC_FAIL == dc.code) {
		OMIP_LOG_DEBUG("vc:%d, code:%d", vc, dc.code);
	}

	BACnet_Service_Request_t bacnet =sptr->paras.choice.bacnet;
	print_debug(OMIP_INFO,"msg mid:%ld, cmd:%ld\r\n", sptr->mid, sptr->cmd);
	if(sptr->cmd ==Cmd_readPropertyMultiple) //读取多个点位
	{
		ReadPropertyMultiple_Request_t readPropertyMultiple =bacnet.choice.readPropertyMultiple;
		int count =readPropertyMultiple.listOfReadAccessSpecs.list.count;
		count =(count>60 ? 60 : count);
		int *obj_ids =calloc_asn(count, sizeof(int));
		for(int i = 0; i < count; i++)
		{
			obj_ids[i] = get_int_by_buf(readPropertyMultiple.listOfReadAccessSpecs.list.array[i][0].objectIdentifier.buf);
		}
		read_multi_property_rsp(vc, obj_ids, sptr->mid,count,sptr->nodeId, rsp_cmd); //读取点位值
		free(obj_ids);
	}
	else if(sptr->cmd ==Cmd_writeProperty) //写点位
	{
		WriteProperty_Request_t writeProperty = bacnet.choice.writeProperty;
		int obj_id = get_int_by_buf(writeProperty.objectIdentifier.buf);
		double real_value = writeProperty.propertyValue.choice.realValue;
		int priority = *writeProperty.priority;
		OMIP_LOG_INFO("obj_id:%d, real_value:%d(x1000), priority:%d\r\n", obj_id, (int)(real_value*1000), priority);
		if(priority == 0) //清除优先级
		{
			int arr_index = *writeProperty.propertyArrayIndex;
			vav_remove_priority(obj_id, arr_index);
			write_property_rsp(vc,sptr->mid, 0, sptr->nodeId);
		}
		else
		{
			int success = vav_set_msg_to_priority_arr(obj_id, &(writeProperty.propertyValue), priority); //写入点位值
			if(success) write_property_rsp(vc,sptr->mid, 0, sptr->nodeId);
			else		write_property_rsp(vc,sptr->mid, 31, sptr->nodeId);
		}
	}
	SEQUENCE_free(&asn_DEF_CmdReq, sptr, FALSE);
}

